#include "var_to_xml.h"

static int _rseed = QTime().msecsTo(QTime::currentTime());

void var_to_xml(QXmlStreamWriter & _writer, const QVariant & _variant, const QString & _name)
{
	::qsrand(_rseed++);
	_writer.writeStartElement("element_"
							  + QCryptographicHash::hash(
									  QString::number(_rseed + ::qrand()).toAscii(),
									  QCryptographicHash::Md5)
							  .toHex()
							  );
	_writer.writeAttribute("type_name", _variant.typeName());
	_writer.writeAttribute("type_id", QString::number(_variant.type()));
	if (!_name.isEmpty())
	{
		_writer.writeAttribute("name", _name);
	}
	switch ((int)_variant.type())
	{
	case QVariant::List:
		{
			const QVariantList & _list = _variant.toList();
			_writer.writeAttribute("count", QString::number(_list.count()));
			foreach (const QVariant & _list_entry, _list)
			{
				var_to_xml(_writer, _list_entry);
			}
			break;
		}
	case QVariant::StringList:
		{
			const QStringList & _list = _variant.toStringList();
			_writer.writeAttribute("count", QString::number(_list.count()));
			foreach (const QString & _list_entry, _list)
			{
				var_to_xml(_writer, _list_entry);
			}
			break;
		}
	case QVariant::Map:
		{
			const QVariantMap & _map = _variant.toMap();
			_writer.writeAttribute("count", QString::number(_map.count()));
			foreach (const QString & _key, _map.keys())
			{
				var_to_xml(_writer, _map[_key], _key);
			}
			break;
		}
	case QVariant::Hash:
		{
			const QVariantHash & _hash = _variant.toHash();
			_writer.writeAttribute("count", QString::number(_hash.count()));
			foreach (const QString & _key, _hash.keys())
			{
				var_to_xml(_writer, _hash[_key], _key);
			}
			break;
		}
	case QVariant::String:
		{
			_writer.writeAttribute("value", _variant.toString());
			break;
		}
	default:
		{
			_writer.writeAttribute("value", _variant.toByteArray().toBase64());
			break;
		}
	}
	_writer.writeEndElement();
}

void xml_to_var(QXmlStreamReader & _reader, QVariant & _variant, QString & _name)
{
	while (_reader.readNext() != QXmlStreamReader::StartElement)
	{
		if (_reader.atEnd())
		{
			_variant.convert(QVariant::Invalid);
			return;
		}
	}
	const QXmlStreamAttributes & _attributes = _reader.attributes();
	_name = _attributes.value("name").toString();
	if (!_attributes.hasAttribute("type_id"))
	{
		_variant.convert(QVariant::Invalid);
		return;
	}
	int _count = _attributes.value("count").toString().toInt();
	QVariant _list_entry;
	QString _entry_name;
	int _type = _attributes.value("type_id").toString().toInt();
	switch (_type)
	{
	case QVariant::List:
		{
			QVariantList _list;
			for (int _idx = 0; _idx < _count; _idx++)
			{
				xml_to_var(_reader, _list_entry, _entry_name);
				_list << _list_entry;
			}
			_variant = _list;
			break;
		}
	case QVariant::StringList:
		{
			QStringList _list;
			for (int _idx = 0; _idx < _count; _idx++)
			{
				xml_to_var(_reader, _list_entry, _entry_name);
				_list << _list_entry.toString();
			}
			_variant = _list;
			break;
		}
	case QVariant::Map:
		{
			QVariantMap _map;
			for (int _idx = 0; _idx < _count; _idx++)
			{
				xml_to_var(_reader, _list_entry, _entry_name);
				_map[_entry_name] = _list_entry;
			}
			_variant = _map;
			break;
		}
	case QVariant::Hash:
		{
			QVariantHash _hash;
			for (int _idx = 0; _idx < _count; _idx++)
			{
				xml_to_var(_reader, _list_entry, _entry_name);
				_hash[_entry_name] = _list_entry;
			}
			_variant = _hash;
			break;
		}
	case QVariant::String:
		{
			_variant = _attributes.value("value").toString();
			break;
		}
	default:
		{
			(_variant = QByteArray::fromBase64(_attributes.value("value").toString().toAscii())).convert((QVariant::Type)_type);
			break;
		}
	}
}

// ----------------------------------------------------------------------

QXmlStreamWriter & operator << (QXmlStreamWriter & _writer, const QVariant & _variant)
{
	var_to_xml(_writer, _variant);
	return _writer;
}

QXmlStreamReader & operator >> (QXmlStreamReader & _reader, QVariant & _variant)
{
	QString _name;
	xml_to_var(_reader, _variant, _name);
	return _reader;
}

// ----------------------------------------------------------------------

